#ifndef PW_PBL_COROUTINE_CORE_HPP
#define PW_PBL_COROUTINE_CORE_HPP

#include <coroutine>
#include <concepts>
#include <cstdlib>
#include <type_traits>
#include <utility>
#include <optional>
#include <cstdint>
#include "../RustMimic.hpp"

#if __has_include("config/pw_pbl/Coroutine.hpp")
#	include "config/pw_pbl/Coroutine.hpp"
#elif __has_include("config/pw_pbl/config.hpp")
#	include "config/pw_pbl/config.hpp"
#else
#	include "../default-config/Coroutine.hpp"
#endif

/// 协程名字空间
/// @note 本库的协程使用类似Javascript的单线程模型，多线程使用时各线程均可开启自己的协程执行器，
/// 但各线程的协程之间通信时需要另加同步机制，尤其注意co_await另一个线程的协程或等待器并不安全
namespace pw_pbl::co
{
	/// 协程模板类
	/// @tparam P 协程完成后返回的对象类型
	/// @note Task<>不拥有协程handle，协程运行到结束自行销毁，不可co_await，注意：Task<void>仍可co_await，只是结果是void
	/// @note 当sizeof...(P) >= 2时，Task<P...>相当于Task<std::tuple<P...>>
	/// @note Optional<P>相当于Task<std::optional<P>>，当sizeof...(P) >= 2时，Optional<P...>相当于Task<std::optional<std::tuple<P...>>>
	/// @note 使用Optional<P...>可实现是否有返回值检查，因为默认将异常屏蔽，只能通过如此来检查异常
	template <typename... P>
	struct Task;

	/// Task<std::optinoal<P>>或Task<std::optional<std::tuple<P...>>>的便捷声明
	template <typename... P> requires(sizeof...(P) >= 1)
	using Optional = Task<std::conditional_t<sizeof...(P) == 1, std::optional<P...>, std::optional<std::tuple<P...>>>>;
} // namespace pw_pbl::co

namespace pw_pbl::_co
{
	template <typename T>
	struct TReturn
	{
		Option<T> value; // 协程未完成前可能提前析构，所以默认需要判断是否已初始化
		constexpr void construct(T v) { value.set(std::forward<T>(v)); }
		constexpr auto &&get() && { return std::move(value).get_unchecked(); }
	};

	template <typename T> requires std::is_trivially_destructible_v<T>
	struct TReturn<T>
	{
		MaybeUninit<T> value;
		constexpr void construct(T v) { value.construct(std::forward<T>(v)); }
		constexpr auto &&get() && { return std::move(value).get(); }
	};

	template <typename T> requires(!std::is_trivially_destructible_v<T> && requires { new ((void *)nullptr) T; })
	struct TReturn<T>
	{
		T value;
		constexpr void construct(T v) { std::destroy_at(&value), std::construct_at(&value, std::forward<T>(v)); }
		constexpr auto &&get() && { return std::forward<T>(value); }
	};

	/// Task的promise基类，假定协程体不发生异常退出
	template <typename... T>
	struct promise_base
	{
		TReturn<std::tuple<T...>> value;
		inline void return_value(T &&...v) { value.construct({std::forward<T>(v)...}); }
		inline decltype(auto) get_result(void) { return std::move(value).get(); }
	};

	template <typename T>
	struct promise_base<T>
	{
		TReturn<T> value;
		inline void return_value(T v) { value.construct(std::forward<T>(v)); }
		inline decltype(auto) get_result(void) { return std::move(value).get(); }
	};

	template <typename T>
	struct promise_base<T &>
	{
		T *pValue;
		inline void return_value(T &v) { pValue = &v; }
		inline T &get_result(void) { return *pValue; }
	};

	template <>
	struct promise_base<>
	{
		inline void return_void(void) {}
		inline void get_result(void) {}
	};

	template <>
	struct promise_base<void>
	{
		inline void return_void(void) {}
		inline void get_result(void) {}
	};

	struct Void
	{
	};

	template <typename R>
	using voidable_parm = std::conditional_t<std::is_void_v<R>, Void, R>;

	struct noncopyable
	{
		noncopyable() = default;
		noncopyable(noncopyable &&) = default;
		noncopyable(const noncopyable &) = delete;
		noncopyable &operator=(const noncopyable &) = delete;
		noncopyable &operator=(noncopyable &&) = default;
	};

	struct dummy_handle
	{
		dummy_handle() = default;
		template <typename T>
		constexpr dummy_handle(T &&) noexcept {}

		template <typename T>
		static constexpr dummy_handle from_promise(T &&) noexcept { return {}; }
	};

	struct suspend_destory
	{
		bool await_ready() noexcept { return false; }
		void await_suspend(std::coroutine_handle<> hdl) noexcept { hdl.destroy(); }
		void await_resume() noexcept {}
	};

	struct destroy_awaitor
	{
		std::coroutine_handle<> hdl;
		bool await_ready() noexcept { return hdl.done(); }
		void await_resume() noexcept { hdl.destroy(); }
	};

	template <typename... T>
	struct once_awaitor
	{
		uint8_t cnt = 0;
		bool await_ready() noexcept { return cnt++; }
		void await_resume() noexcept {}
	};

	template <typename T>
	struct get_handler_awaitor
	{
		T obj;
		inline constexpr bool await_ready() noexcept { return true; }
		inline constexpr void await_suspend(std::coroutine_handle<>) noexcept {}
		inline constexpr T await_resume() noexcept { return obj; }
	};

	class get_handler_tag
	{
		explicit constexpr get_handler_tag() = default;

	public:
		static constexpr get_handler_tag get() noexcept { return get_handler_tag{}; }
	};

	/// 协程等待器模板类，本库协程中当co_await使用await_transform时使用此模板类推导并构造对象
	template <typename T>
	struct FullAwaitor;
} // namespace pw_pbl::_co

namespace pw_pbl::co
{
	/// 用于通过co_yield在协程内部获取协程handle的标记值
	constexpr auto HandleGetter = _co::get_handler_tag::get();

	/// 用于分享执行时间的标记操作，co_await Yield();会挂起当前协程，由执行器决定何时继续执行
	/// @note 通常用于协程长循环中主动分享执行时间
	/// @note 也常用在协程起始，相当于将协程延迟执行
	constexpr auto Yield = [] { return _co::once_awaitor<>{}; };

	/// 延迟协程，创建后立即挂起等待下个tick才开始执行，除此外其它与原协程相同
	/// @tparam T 协程类型
	template <typename T>
	struct Defer : public T
	{
		struct promise_type : public T::promise_type
		{
			inline static auto get_return_object_on_allocation_failure(void) { return Defer{T::promise_type::get_return_object_on_allocation_failure()}; }
			inline auto get_return_object(void) { return Defer{T::promise_type::get_return_object()}; }
			inline auto initial_suspend(void) { return _co::FullAwaitor{_co::once_awaitor<T>{}}; }
		};
	};

	/// 协程注入，在协程的promise注入指定类型的数据，通常使用构造函数和析构函数来添加自定义动作
	template <typename T, typename... P> requires(std::is_default_constructible_v<P> && ...)
	struct Inject : public T
	{
		using T::T;
		constexpr Inject(T obj) : T(std::move(obj)) {}
		struct promise_type : public P..., public T::promise_type
		{
			using T::promise_type::promise_type;
			inline static auto get_return_object_on_allocation_failure(void) { return Inject{T::promise_type::get_return_object_on_allocation_failure()}; }
			inline auto get_return_object(void) { return Inject{T::promise_type::get_return_object()}; }
		};

		using Defer = Defer<Inject>;
	};

	/// 分离指定的协程或等待器
	template <typename... T>
	void Detach(T &&...co) requires(!std::is_reference_v<T> && ...);

	template <typename... T>
	struct Task
	{
		static constexpr bool EOwnHandle = sizeof...(T) != 0;
		struct promise_type;

	private:
		using handle_type = std::conditional_t<EOwnHandle, std::coroutine_handle<promise_type>, _co::dummy_handle>;
		handle_type handler [[no_unique_address]];

		inline Task(handle_type h) : handler(h) {}

		explicit constexpr Task() requires EOwnHandle : handler(nullptr) {}
		friend Option<Task>;

	public:
		inline Task(Task &&old) noexcept requires EOwnHandle : handler(std::exchange(old.handler, nullptr)) {}
		inline ~Task(void) noexcept requires EOwnHandle { handler ? handler.destroy() : void(); }

		explicit constexpr Task() requires(!EOwnHandle) = default;
		Task(const Task &) noexcept requires(!EOwnHandle) = default;
		inline ~Task(void) noexcept requires(!EOwnHandle) = default;

		Task &operator=(const Task &) = delete;
		inline void operator=(Task &&old) noexcept requires EOwnHandle { this->~Task(), new (this) Task{std::forward<Task>(old)}; }

		inline void Detach(void) noexcept requires EOwnHandle { Detach(_co::destroy_awaitor{std::exchange(handler, nullptr)}); }

		/// 创建后立即挂起等待下个tick才开始执行
		using Defer = co::Defer<Task>;

		/// 在协程的promise注入指定类型的数据，通常使用构造函数和析构函数来添加自定义动作
		template <typename... P>
		using Inject = co::Inject<Task, P...>;

		inline explicit constexpr operator bool() const noexcept requires EOwnHandle { return bool{handler}; }
		inline bool Done() noexcept requires EOwnHandle { return handler.done(); }
		inline decltype(auto) Result() noexcept requires EOwnHandle { return handler.promise().get_result(); }

		inline bool await_ready() noexcept requires EOwnHandle { return handler.done(); }
		inline decltype(auto) await_resume() noexcept requires EOwnHandle { return handler.promise().get_result(); }
	};

	template <typename... T>
	struct Task<T...>::promise_type : public _co::promise_base<T...>, public co::InjectedPromiseBase<promise_type>
	{
		using _co::promise_base<T...>::promise_base;

		template <typename SELF>
		inline auto yield_value(this SELF &self, _co::get_handler_tag) { return _co::get_handler_awaitor<std::coroutine_handle<SELF>>{std::coroutine_handle<SELF>::from_promise(self)}; }
		inline static auto get_return_object_on_allocation_failure(void) { return Task{nullptr}; }
		inline auto get_return_object(void) { return Task{handle_type::from_promise(*this)}; }
		inline auto initial_suspend(void) { return std::suspend_never{}; }
		inline std::suspend_always final_suspend(void) noexcept requires EOwnHandle { return {}; }
		inline _co::suspend_destory final_suspend(void) noexcept requires(!EOwnHandle) { return {}; }
		inline void unhandled_exception(void) { std::abort(); }

		template <typename F>
		inline decltype(auto) await_transform(F &&f) { return _co::FullAwaitor{std::forward<F>(f)}; }
	};

	/// 分离指定的协程或等待器
	template <typename... T>
	inline void Detach(T &&...co) requires(!std::is_reference_v<T> && ...)
	{
		static_assert(sizeof...(T) >= 1);
		[](T... co) mutable -> Task<> { ((co_await co), ...); }(std::forward<T>(co)...);
	}

	/// 生成器类模板
	/// @tparam T 生成的数据类型
	template <typename T>
	class Generator
	{
	public:
		struct promise_type;

	private:
		using handle_type = std::coroutine_handle<promise_type>;
		handle_type handle;
		inline Generator(handle_type h) : handle(h) {}

	public:
		Generator(const Generator &) = delete;
		constexpr Generator(Generator &&oth) noexcept : handle{std::exchange(oth.handle, nullptr)} {}
		~Generator() noexcept { handle ? handle.destroy() : (void)handle; }
		inline bool Done() const noexcept { return !handle || handle.done(); }

	public:
		struct end_itor
		{};
		class Itor;
		Itor begin() noexcept { return {handle}; }
		end_itor end() noexcept { return {}; }
	};

	template <typename T>
	class Generator<T>::Itor
	{
		handle_type handle;
		constexpr Itor(handle_type h) noexcept : handle{h} {}
		friend Generator;

	public:
		constexpr bool operator==(end_itor) noexcept { return handle.done(); }
		constexpr bool operator!=(end_itor) noexcept { return !handle.done(); }
		using iterator_category = std::input_iterator_tag;
		using value_type = T;
		using difference_type = std::ptrdiff_t;
		using pointer = T *;
		using reference = T &;

		inline Itor &operator++() { return handle.resume(), *this; }

		struct vitor
		{
			value_type value;
			inline decltype(auto) operator*() { return std::forward<value_type>(value); }
		};

		inline vitor operator++(int)
		{
			vitor it{**this};
			++*this;
			return it;
		}

		inline decltype(auto) operator*() const { return std::forward<value_type>(handle.promise().value); }
	};

	template <typename T>
	struct Generator<T>::promise_type : public std::suspend_always
	{
		T value;
		inline void return_void(void) {}
		inline decltype(auto) yield_value(T v) noexcept { return (value = std::forward<T>(v)), *this; }
		inline auto yield_value(_co::get_handler_tag) { return _co::get_handler_awaitor<handle_type>{handle_type::from_promise(*this)}; }
		inline static auto get_return_object_on_allocation_failure(void) { return Generator{nullptr}; }
		inline auto get_return_object(void) { return Generator{handle_type::from_promise(*this)}; }
		inline auto initial_suspend(void) { return std::suspend_never{}; }
		inline auto final_suspend(void) noexcept { return *this; }
		inline void unhandled_exception(void) {}

		template <typename... F>
		inline decltype(auto) await_transform(F &&...) { static_assert(sizeof...(F) == 0, "pure generator can't co_await, maybe use Function<T> instead"); }
	};

} // namespace pw_pbl::co

namespace pw_pbl
{
	template <typename... T> requires(sizeof...(T) != 0)
	class Option<co::Task<T...>> : public Option<std::type_identity<co::Task<T...>>>
	{
		co::Task<T...> raw;

	public:
		constexpr Option() = default;
		constexpr Option(co::Task<T...> data) : raw(std::move(data)) {}
		constexpr bool is_none() const { return !raw; }
		constexpr co::Task<T...> &get_unchecked() & { return raw; }
		constexpr const co::Task<T...> &get_unchecked() const & { return raw; }
		constexpr co::Task<T...> &&get_unchecked() && { return std::move(raw); }
	};
} // namespace pw_pbl

#endif // PW_PBL_COROUTINE_CORE_HPP
